Skip to content

transform/subslice: Add subslice transform #14643

Closed
jlucovsky wants to merge 2 commits intoOISF:mainfrom
jlucovsky:7672/12
Closed

transform/subslice: Add subslice transform #14643
jlucovsky wants to merge 2 commits intoOISF:mainfrom
jlucovsky:7672/12

Conversation

@jlucovsky
Copy link
Contributor

Continuation of #14625

The subslice transform creates a slice of the input buffer.

Specify the subslice desired -- nbytes and truncate are optional:
        subslice: offset <,nbytes> <,truncate>

offset: Specifies the starting offset for the new subslice. When
negative, expresses how far from the end of the input buffer to begin.
When nbytes is *not* specified, start must be > 0.

nbytes: Specifies the size of the subslice. When negative, specifies the
byte count preceding the offset to include. Nbytes must be > 0.

When nbytes is not specified, the size of the subslice will be the size
of the input buffer - offset.

truncate: Specify behavior when offset + nbytes exceeds buffer length.
When present, trims nbytes such that offset + nbytes equals buffer
length. When not present, an empty buffer is produced.

Examples:
subslice: 1; - The subslice will be a copy of the input
buffer but omit the input buffer's first byte
"This is Suricata" -> "his is Suricata"
subslice: 0, 13; - The slice is created from the first 13 bytes
of the input buffer
"This is Suricata" -> "This is Suric"
subslice: 10, -5; - This is the same as subslice[5, 5]
"This is Suricata" -> "is Su"
subslice: -3; - The subslice will be the last 3 bytes of the
input buffer.
"This is Suricata" -> "ata"

Link to ticket: https://redmine.openinfosecfoundation.org/issues/7672

Describe changes:

  • Add subslice transform and unit tests
  • Document subslice transform, with examples

Updates:

  • Removed support for bracketed values, e.g., [3], [3, 8]`
  • Changed function DetectTransformSubsliceData to be attributed with repr(C)
  • Modified handling of negative nbyte values to mean "bytes from the end" .
  • start=0 is an error unless nbytes is specified
  • end=0 is always an error.
  • Corrected clippy issues.
  • Added configuration variable subslice.truncate to control behavior when offset + nbytes > length
  • Updated s-v branch.
  • Fixed s-v failing tests due to default config settings
  • Rebase
  • Fixed race condition in unittests wrt global variable
  • Removed truncate global option and replaced with a per-usage truncate option.
  • Rebase
  • Doc update to remove lingering global truncate option.
  • Removed commit that adjusted asn1 underline characters.
  • Updated Rust unit tests to eliminate is_some usage.
  • Removed inadvertent inclusion of Cargo.lock.in

Provide values to any of the below to override the defaults.

  • To use a Suricata-Verify or Suricata-Update pull request,
    link to the pull request in the respective _BRANCH variable.
  • Leave unused overrides blank or remove.

SV_REPO=
SV_BRANCH=OISF/suricata-verify#2749
SU_REPO=
SU_BRANCH=

Issue: 7672

The subslice transform creates a slice of the input buffer.

Specify the subslice desired -- nbytes and truncate are optional:
        subslice: offset <,nbytes> <,truncate>

offset: Specifies the starting offset for the new subslice. When
negative, expresses how far from the end of the input buffer to begin.
When nbytes is *not* specified, start must be > 0.

nbytes: Specifies the size of the subslice. When negative, specifies the
byte count preceding the offset to include. Nbytes must be > 0.

When nbytes is not specified, the size of the subslice will be the size
of the input buffer - offset.

truncate: Specify behavior when offset + nbytes exceeds buffer length.
When present, trims nbytes such that offset + nbytes equals buffer
length. When not present, an empty buffer is produced.

Examples:
        subslice: 1;     - The subslice will be a copy of the input
            buffer but omits the input buffer's first byte
            "This is Suricata" -> "his is Suricata"
        subslice: 0, 13; - The slice is created from the first 13 bytes
            of the input buffer
            "This is Suricata" -> "This is Suric"
        subslice: 10, -5; - The subslice is created starting at offset 10
            and continues to 5 bytes before the end of the input buffer
            "This is Suricata" -> "r"
        subslice: -3; - The subslice will be the last 3 bytes of the
            input buffer.
            "This is Suricata" -> "ata"
Add documentation for the subslice transform.

Issue: 7672
@codecov
Copy link

codecov bot commented Jan 17, 2026

Codecov Report

❌ Patch coverage is 96.11231% with 18 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.37%. Comparing base (c333b28) to head (1be40af).
⚠️ Report is 33 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #14643      +/-   ##
==========================================
+ Coverage   82.11%   82.37%   +0.25%     
==========================================
  Files        1011     1012       +1     
  Lines      262812   267341    +4529     
==========================================
+ Hits       215812   220214    +4402     
- Misses      47000    47127     +127     
Flag Coverage Δ
fuzzcorpus 60.68% <10.59%> (+0.49%) ⬆️
livemode 18.69% <10.59%> (-0.02%) ⬇️
pcap 45.17% <10.59%> (+0.57%) ⬆️
suricata-verify 65.61% <81.33%> (+0.33%) ⬆️
unittests 59.25% <87.22%> (-0.02%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@suricata-qa
Copy link

Information: QA ran without warnings.

Pipeline = 29172

@suricata-qa
Copy link

Information: QA ran without warnings.

Pipeline = 29301

Copy link
Contributor

@catenacyber catenacyber left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the work,

CI : ✅
Code : looking now
Commits segmentation : I would squash but ok
Commit messages : nice
Git ID set : looks fine for me
CLA : you already contributed
Doc update : cool
Redmine ticket : ok
Rustfmt : no rust
Tests : left some comments on SV PR
Dependencies added: none

than the input buffer size. When specified, the result will
be trimmed as though ``offset + nbyfes == buffer_length``. When
not specified [DEFAULT], an empty buffer will be produced on
which ``bsize:0`` will match. [OPTIONAL]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explicit more the behavior of truncate when we have negative values ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will add discussion.

# The default is to truncate (on). Set to off to not truncate and produce an
# empty buffer (bsize:0 will match).
subslice:
truncate: on
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do not need this anymore, right ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct. Will remove.

truncate: true,
})
}
_ => None,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you log a friendly error ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do.


// copy result into output
let len = slice.len();
output[..len].copy_from_slice(slice);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this work in-place ? If input and output are the same pointer/buffer ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will research.

let len = data.len() as isize;

// Reject impossible offsets
if ctx.offset.abs() > len {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

even if ctx.truncate ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This condition catches an offset value (+ or -) that exceeds the length of the buffer.

Suppose the buffer is "This is Suricata" (length 16 chars)

subslice: -17, -3, truncate

  • Subslice begins before the buffer (does this make sense?)
  • Subslice terminates 3 chars from the end
    Should the transform treat this as though subslice: 0, -3 because truncate was used?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suppose the buffer is "This is Suricata" (length 16 chars)

I would expect subslice: -17, -truncate to give me the full buffer. Truncate goes both ways : end and beginning
Do you expect differently ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed -- i'll update things.

Copy link
Contributor

@catenacyber catenacyber left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See inline like

Correct. Will remove.

@jlucovsky
Copy link
Contributor Author

Continued in #14751

@jlucovsky jlucovsky closed this Feb 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants